//
//  WDRouter.swift
//  WDRouter
//
//  Created by Alean on 2023/3/28.
//

import UIKit

@objc public protocol WDRouterable: NSObjectProtocol {
//    static var routerPage: WDRouterPage { get }
//    static var routeAnimation: WDAnimationOC { get }
    static func routerPageCreate(scheme: String?, parameters: [String: String]?, object: Any?) -> AnyObject?
}

//fatalError("num不能小于0")无法通过do-catch捕捉
public enum WDRouterError: Error {
    case errorNormal(Int, String) //正常错误
    case errorDesc(String)   //错误带描述
    case errorCode(Int) //错误只包含code
}

//Handler: @escaping () -> Void “逃逸” 闭包需要在函数返回之后被调用
//public typealias RouterResultHandler = (_ object: AnyObject?, _ desc: String) -> Void

open class WDRouter: NSObject {
    
    /// 应用内路由跳转
    /// - Parameters:
    ///   - maping: 约定字段
    ///   - params: 参数
    ///   - object: 而外的对象
    ///   - type: 默认对比类型 WDRouterable.self 可以定义其他的 比如 UIViewController.self
    ///   - routerResultHandler: 如果成功返回对应的type 类型实例数据
    @objc open class func router(maping: String,
                                 params: [String: String]? = nil,
                                 object: Any? = nil) throws -> Any {
        return try WDRouterManager.router(maping: maping,
                                          params: params,
                                          object: object)
    }
    
    /// url 路由跳转 scheme2://page/VC1?title=push xib创建的vc",
    /// - Parameters:
    ///   - urlString: 特定的url地址
    ///   - routerResultHandler: 如果成功返回对应的type 类型实例数据
    @objc open class func router(urlString: String) throws -> Any {
        return try WDRouterManager.router(urlString: urlString)
    }

    @objc open class func router(className: String,
                                 target: String,
                                 scheme: String = "",
                                 params: [String: String]? = nil,
                                 object: Any? = nil) throws -> Any {
        return try WDRouterManager.router(className: className,
                                          target: target,
                                          scheme: scheme,
                                          params: params,
                                          object: object)
    }
    
    /// 检查urlString是否是合法scheme
    @objc open class func validateUrl(_ urlString: String) -> Bool {
        return WDRouterManager.validatePageUrl(urlString)
    }

}

public extension WDRouter {
    /// 配置基本参数
    /// - Parameters:
    ///   - schemes: 如果需要url router 必须使 schemes和hosts 不为空
    ///   - hosts: 如果需要url router 必须使 schemes和hosts 不为空
    ///   - pagePathMap: 如果只是需要内部router 以上两个参数可为空
    @objc static func setup(schemes: [String]? = nil,
                            hosts: [String]? = nil,
                            pagePathMap: [String: [String: String]]) {
        
        if let schemes = schemes, let hosts = hosts {
            WDRouterManager.setup(schemes: schemes, hosts: hosts)
        }
        WDRouterManager.setup(pagePathMap: pagePathMap)
    }
}

class WDRouterManager {
    static let shared = WDRouterManager()
    /// 合法schemes
    static private(set) var schemes: [String] = ["woody"]
    /// 合法hosts
    static private(set) var hosts: [String] = ["page"]
    /// 约定的字符串和对应[target: progect] 的映射表
    static private(set) var pagePathMap = [String: [String: String]]()

    class func router(urlString: String) throws -> AnyObject? {
        if schemes.isEmpty || hosts.isEmpty {
            fatalError("schemes/hosts 不能为空,请调用 WDRouter.setup 配置")
            return nil
        }
        guard let urlStr = urlString.urlEncoded(),
              let url = urlStr.toURL() else {
            throw WDRouterError.errorNormal(-300, "\(urlString) is not urlstring")
            return nil
        }
        // 约定的字符串
        let mappingWord = url.lastPathComponent
        if mappingWord.isEmpty {
            throw WDRouterError.errorDesc("\(urlString) 没有约定字符串")
        } else {
            if validatePageUrl(urlStr) {
                let queryParameters = url.queryParameters
                return try router(maping: mappingWord,
                                  params: queryParameters,
                                  object: urlString)
            } else {
                throw WDRouterError.errorDesc("\(urlString) 是非正常跳转url")
            }
        }
    }

    class func router(className: String,
                      target: String,
                      scheme: String,
                      params: [String: String]? = nil,
                      object: Any? = nil) throws -> AnyObject? {
        if let result = try WDRouterManager.getClass(className: className, target: target),
           let cls = result.0 {
            if let VC = (cls as? WDRouterable.Type)?.routerPageCreate(scheme: scheme, parameters: params, object: object) {
                return VC
            } else if let vc = (cls as? NSObject.Type) {
                let controller = vc.init()
                return controller
            } else {
                throw WDRouterError.errorNormal(-404, "非规定类型 WDRouterable 或者 NSObject")
            }
        } else {
            throw WDRouterError.errorNormal(-300, "Create routerPage failed")
        }
    }

    // let type = AnyObject.self//WDRouterable.self
    class func router(maping: String,
                      params: [String: String]? = nil,
                      object: Any? = nil) throws -> AnyObject? {
        if pagePathMap.isEmpty {
            fatalError("pagePathMap 不能为空,请调用 WDRouter.setup 配置")
            return nil
        }
        if pagePathMap.keys.contains(maping), let map = pagePathMap[maping] {
            if let target = map.keys.first, let className = map[target] {
                return try router(className: className,
                                  target: target,
                                  scheme: maping,
                                  params: params,
                                  object: object)
            } else {
                throw WDRouterError.errorDesc("\(maping) 在map = \(map) 中 未找到")
            }
        } else {
            throw WDRouterError.errorDesc("\(maping) 未注册的mapping:")
        }
    }
    
    private class func getClass(className: String,
                                target: String) throws -> (AnyClass?, String)? {
        
        func incrementer(cls: Any) -> (AnyClass?, String) {
            var tips = ""
            let clsR = cls as? AnyClass
            if clsR == nil {
                tips = "不是 \(AnyClass.self) 类型: "
            }
            return (clsR, tips)
        }

        let cName = (target + "." + className).replacingOccurrences(of: "-", with: "_")
        if let childVcClass = NSClassFromString(cName) {//表示判断swift的类
            let x = incrementer(cls: childVcClass)
            if x.0 == nil {
                throw WDRouterError.errorDesc(x.1 + cName)
            }
            return x
        } else if let c = NSClassFromString(className) {//表示判断是否oc的类
            let x = incrementer(cls: c)
            if x.0 == nil {
                throw WDRouterError.errorDesc(x.1 + cName)
            }
            return x
        } else {
            throw WDRouterError.errorDesc("没有获取到对应的class: " + cName)
        }
        return nil

    }
//    private class func getClass(className: String, project: String) throws -> (WDRouterable.Type?, String)? {
//
//        func incrementer(cls: AnyClass) -> (WDRouterable.Type?, String) {
//            var tips = ""
//            let childVcType = cls as? UIViewController.Type
//            if childVcType == nil {
//                tips = "不是 UIViewController : "
//            }
//            let clsR = cls as? WDRouterable.Type
//            if clsR == nil {
//                tips = "没有遵循 WDRouterable : "
//            }
//            return (clsR, tips)
//        }
//
//        let cName = (project + "." + className).replacingOccurrences(of: "-", with: "_")
//        if let childVcClass = NSClassFromString(cName) {//表示判断swift的类
//            let x = incrementer(cls: childVcClass)
//            if x.0 == nil {
//                throw WDRouterError.errorDesc(x.1 + cName)
//            }
//            return x
//        } else if let c = NSClassFromString(className) {//表示判断是否oc的类
//            let x = incrementer(cls: c)
//            if x.0 == nil {
//                throw WDRouterError.errorDesc(x.1 + cName)
//            }
//            return x
//        } else {
//            throw WDRouterError.errorDesc("没有获取到对应的class: " + cName)
//        }
//        return nil
//    }

    static func setup(schemes: [String], hosts: [String]) {
        WDRouterManager.hosts = hosts
        WDRouterManager.schemes = schemes
    }
    
    static func setup(pagePathMap: [String: [String: String]]) {
        WDRouterManager.pagePathMap = pagePathMap
    }

    /// 检查urlString是否是合法page schema
    static func validatePageUrl(_ urlString: String) -> Bool {
        guard let url = urlString.toURL(),
              let scheme = url.scheme,
              schemes.contains(scheme),
              let host = url.host,
              hosts.contains(host) else {
            return false
        }
        return true
    }
}

extension String {
    var isNotBlank: Bool {
        let trimmed = trimmingCharacters(in: .whitespacesAndNewlines)
        return !trimmed.isEmpty
    }
    
    func urlEncoded() -> String? {
        return addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
    }
    
    func urlDecoded() -> String? {
        return removingPercentEncoding
    }
    
    func toURL() -> URL? {
        return URL(string: self)
    }
}

extension URL {
    var queryParameters: [String: String]? {
        guard let components = URLComponents(url: self, resolvingAgainstBaseURL: true), let queryItems = components.queryItems else {
            return nil
        }
        var parameters = [String: String]()
        for item in queryItems {
            parameters[item.name] = item.value
        }
        return parameters
    }
}
//public protocol WisdomRouterRegisterProtocol {
//
//    //MARK: - Register Router Protocol
//    static func registerRouter()
//}
//open class WDRouter: NSObject {
////    @objc static public func routerKitFunction() {
////        let typeCount = Int(objc_getClassList(nil, 0))
////        let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
////        let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
////        objc_getClassList(autoreleasingTypes, Int32(typeCount))
////        print("typeCount = \(typeCount)")
////        for index in 0 ..< typeCount {
////            (types[index] as? WisdomRouterRegisterProtocol.Type)?.registerRouter()
////        }
////        types.deallocate()
////    }
//
//    public typealias Completion = (Bool, Any?) -> Void
//    /// 支持的schemes
//    public static private(set) var schemes = [""]
//    public static private(set) var pageHost = "page"
//
//    typealias ClassName = String
//    typealias PageName = String
//    /// 类名和枚举值的映射表
//    static var pagePathMap = [PageName: ClassName]()
//
//    /// 检查urlString是否是合法page schema
//    static func validatePageUrl(_ urlString: String) -> Bool {
//        guard let url = urlString.toURL(),
//            let scheme = url.scheme,
//            schemes.contains(scheme),
//            url.host == WDRouter.pageHost else {
//                return false
//        }
//        return true
//    }
//
//    /// 检查urlString是否是合法scheme
//    @objc static public func validateUrl(_ urlString: String) -> Bool {
//        return validatePageUrl(urlString)
//    }
//    /// 遍历所有的类，检测是否实现Routable，存入字典作为映射表，使用Router前必须先调用
//    @objc static public func setup(_ appDelegate: UIApplicationDelegate,
//                                   schemes: [String],
//                                   pageHost: String = "page") {
//        WDRouter.pageHost = pageHost
//        WDRouter.schemes = schemes
//        WDRouter.registerPathMap(appDelegate)
//    }
//
//    @objc static public func page(_ page: WDPage) -> WDRouterPage {
//        return WDPageObject(rawValue: "\(page.rawValue)") as! WDRouterPage
//    }
//    /// 遍历所有的类，检测是否实现Routable，存入字典作为映射表，使用Router前必须先调用
//    static func registerPathMap(_ appDelegate: UIApplicationDelegate) {
//        let start = Date().timeIntervalSince1970
////        let start = CACurrentMediaTime()
//
////        let typeCount = Int(objc_getClassList(nil, 0))
////        let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
////        let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
////        objc_getClassList(autoreleasingTypes, Int32(typeCount))
//////        print("typeCount = \(typeCount)")
////        for index in 0 ..< typeCount {
////            (types[index] as? WisdomRouterRegisterProtocol.Type)?.registerRouter()
////        }
////        types.deallocate()
////
////        let end = Date().timeIntervalSince1970
//////        let end = CACurrentMediaTime()
////        print("方法耗时为：\(end - start)")
////
////        return
//
//        var count: UInt32 = 0
//        /// objc_copyImageNames 获取所有加载的Objective-C框架和动态库的名称
//        /// class_getImageName 获取指定类所在动态库
//        /// objc_copyClassNamesForImage 获取指定库或框架中所有类的类名
//        guard let image = class_getImageName(object_getClass(appDelegate)),
//            let classes = objc_copyClassNamesForImage(image, &count) else {
//                print("WDRouter registerPathMap failed!!!!!!!!!!!!!!!!!!")
//                return
//        }
//        print("count = \(count)")
//        for i in 0 ..< Int(count) {
//            print(String(cString: classes[i], encoding: .utf8))
//            if let clsName = String(cString: classes[i], encoding: .utf8)?.components(separatedBy: ".").last {
//                print("clsName = \(clsName)")
//                print("clsName1 = \(clsName.toClass())")
//                if let cls = clsName.toClass() as? WDRouterable.Type {
//                    print(cls.routerPage.rawValue)
//                    pagePathMap.updateValue(clsName, forKey: cls.routerPage.rawValue)
//                    print("pagePathMap = \(pagePathMap)")
//                }
//            }
//        }
//        let end = Date().timeIntervalSince1970
////        let end = CACurrentMediaTime()
//        print("方法耗时为：\(end - start)")
//
//    }
//}
//
//public extension String {
//    var isNotBlank: Bool {
//        let trimmed = trimmingCharacters(in: .whitespacesAndNewlines)
//        return !trimmed.isEmpty
//    }
//
//    func urlEncoded() -> String? {
//        return addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
//    }
//
//    func urlDecoded() -> String? {
//        return removingPercentEncoding
//    }
//
//    func toURL() -> URL? {
//        return URL(string: self)
//    }
//
//    func toClass() -> AnyClass? {
//        let url = Bundle.main.url(forResource: "WDFavourModule", withExtension: "bundle")
//        let bundle = Bundle(url: url!)
//
////        if  let appName: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleName") as? String {
//        if let appName = bundle?.object(forInfoDictionaryKey: "CFBundleName") as? String {
//            let classStringName = "_TtC\(appName.count)\(appName)\(self.count)\(self)"
//            let cls: AnyClass? = NSClassFromString(classStringName)
//            print("appName = \(appName) cls = \(cls) classStringName = \(classStringName)")
//            return cls
//
////            if let cls: AnyClass = NSClassFromString(classStringName) {
////                print("cls = \(classStringName)")
////                return cls
////            } else {
////                let cls1: AnyClass?  = NSClassFromString("\(self)")
////                print("cls1 = \(cls1)")
////                return cls1
////            }
//        }
//        return nil;
//    }
//}
